package com.example.piece.net

import com.example.base.entity.Rest
import com.example.base.tools.ConfigTool
import com.example.piece.constant.Key
import com.example.piece.entity.User
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import okhttp3.*
import java.util.concurrent.locks.ReentrantLock



/**  Token 头部拦截器, 全局统一添加 token  **/
class TokenInterceptor private constructor(
    private val headerKey: String,
    private val providerToken: ProviderToken
) : Interceptor {

    companion object {
        /**
         * 构建 TokenInterceptor
         * @param headerKey 头部的 key
         * @param providerToken 提供 token 的函数
         */
        fun build(headerKey: String, providerToken: ProviderToken): TokenInterceptor =
            TokenInterceptor(headerKey, providerToken)
    }

    private var lastRefreshTime: Long = 0

    private val lock = ReentrantLock()

    @Synchronized
    override fun intercept(chain: Interceptor.Chain): Response {
        synchronized(TokenInterceptor::class.java) {
            try {
                lock.lock()
                val response = buildNewRequest(chain = chain, oldResponse = null)

                if (response.code == NetManager.TOKEN_INVALID) {
                    // 刷新 token 的间隔小于 1 分钟, 则说明并发重复请求, 直接构建新的请求再次请求
                    /*  val nowTime = System.currentTimeMillis()
                      if (nowTime - lastRefreshTime < 1000)
                          return buildNewRequest(chain, response)*/

                    val rest = refreshToken()

                    /* return if (rest.code != NetManager.DATA_OK) {
                         UIManager.closeApp()
                         navigationTo(RoutePath.MAIN_LOGIN)
                         response
                     } else {
                         Log.e("re login", "new token: ${rest.data.token}")
                         // Update token
                         ConfigTool.putString(Key.DataKey.TOKEN, rest.data.token)

                         // 关闭上次请求, 并重新构建请求, 再次发起请求, 同时把新的 token 带入进去
                         buildNewRequest(chain, response)
                     }*/
                }

                return response
            } finally {
                lock.unlock()
            }
        }
    }

    /**  关闭上一次请求, 构建新的请求并重新进行请求  **/
    private fun buildNewRequest(chain: Interceptor.Chain, oldResponse: Response?): Response {
        oldResponse?.close()
        val newRequest = chain.request().newBuilder()
            .addHeader(headerKey, providerToken())
            .build()
        return chain.proceed(newRequest)
    }

    @Synchronized
    private fun refreshToken(): Rest<User> {
        synchronized(TokenInterceptor::class.java) {
            val client = OkHttpClient()
            val builder = FormBody.Builder()
            builder.add("username", ConfigTool.getString(Key.DataKey.USERNAME))
            builder.add("password", ConfigTool.getString(Key.DataKey.PASSWORD))
            val newRequest = Request.Builder().url(NetManager.getServerLocation() + "user/login")
                .post(builder.build())
                .build()
            val newResponse = client.newCall(newRequest)
                .execute().body!!.string()

            lastRefreshTime = System.currentTimeMillis()
            // 使用了泛型, 必须要用 TypeToken 来解析, 否则会解析失败
            return Gson().fromJson<Rest<User>>(
                newResponse,
                object : TypeToken<Rest<User>>() {
                }.type
            )
        }
    }

}

typealias ProviderToken = () -> String